__author__ = 'drazen.popovic'

from StringIO import StringIO
from datetime import datetime

class Field():
    _value = None
    def setValue(self, value):
        self._value = value
    def getValue(self):
        if self.isEmpty():
            raise ValueError("field is empty")
        return self._value
    def isEmpty(self):
        return self._value == None

class IntField(Field):
    def __init__(self, value):
        if type(value) != int and value != None:
            raise  TypeError("should be int")
        self.setValue(value)

class FloatField(Field):
    def __init__(self, value):
        if type(value) != float and value != None:
            raise  TypeError("should be float")
        self.setValue(value)

class StringField(Field):
    def __init__(self, value):
        if type(value) != str and value != None:
            raise  TypeError("should be string")
        self.setValue(value)

class DatetimeField(Field):
    def __init__(self, value):
        if type(value) != datetime and value != None:
            raise  TypeError("should be datetime")
        self.setValue(value)

class Header():
    APP_ID_SZ = 2
    PKG_SIZE_SZ = 4
    STR_FORMAT = "APP_ID: {0}\nPKG_SIZE: {1}\n"
    _appid = IntField(None)
    _pkgsize = IntField(None)

    def get(self):
        return self.getAppId(), self.getPkgSize()
    def getAppId(self):
        return self._appid.getValue()
    def getPkgSize(self):
        return self._pkgsize.getValue()
    def validateAppId(self, appid):
        pass
    def validatePkgSize(self,pkgsize):
        pass
    def set(self, appid, pkgsize):
        self.setAppId(appid)
        self.setPkgSize(pkgsize)
    def setAppId(self, appid):
        self.validateAppId(appid)
        self._appid.setValue(appid)
    def setPkgSize(self, pkgsize):
        self.validatePkgSize(pkgsize)
        self._pkgsize.setValue(pkgsize)
    def readAppId(self, stream):
        value = int(stream.read(self.APP_ID_SZ))
        self.setAppId(value)
        return value
    def readPkgSize(self, stream):
        value = int(stream.read(self.PKG_SIZE_SZ))
        self.setPkgSize(value)
        return value
    def readFromStream(self, stream):
        self.readAppId(stream)
        self.readPkgSize(stream)
        return self
    def readFromString(self, buff):
        buff_stream = StringIO(buff)
        tell_start = buff_stream.tell()
        self.readFromStream(buff_stream)
        tell_end = buff_stream.tell()
        buff_stream.close()
        return tell_end - tell_start
    def writeAppId(self, stream):
        tell_start = stream.tell()
        stream.write("{0:02d}".format(self.getAppId())[:self.APP_ID_SZ])
        tell_end = stream.tell()
        return tell_end-tell_start
    def writePkgSize(self, stream):
        tell_start = stream.tell()
        stream.write("{0:04d}".format(self.getPkgSize())[:self.PKG_SIZE_SZ])
        tell_end = stream.tell()
        return tell_end-tell_start
    def writeToStream(self, stream):
        tell_start = stream.tell()
        self.writeAppId(stream)
        self.writePkgSize(stream)
        tell_end = stream.tell()
        return tell_end-tell_start
    def __str__(self):
        return self.STR_FORMAT.format(self.getAppId(), self.getPkgSize())

def readField(stream, delimiters):
    strField = ""
    while True:
        c = stream.read(1)
        if c in delimiters:
            break
        strField += c
    return strField

class Body():
    DATETIME_FORMAT = "%Y%m%d%H%M"
    TIMESTAMP_FORMAT = DATETIME_FORMAT + "%S"

    _action_sign = IntField(None)
    _imsi = IntField(None)
    _msisdn = StringField(None)
    _gk_id = StringField(None)
    _ipt_id = StringField(None)
    _status_code = IntField(None)
    _sms_datetime = DatetimeField(None)
    _enterence_datetime = DatetimeField(None)
    _pay_datetime = DatetimeField(None)
    _leave_datetime = DatetimeField(None)
    _exit_datetime = DatetimeField(None)
    _amount = FloatField(None)
    _currency = StringField(None)
    _ipt_id_list = StringField(None)
    _timestamp = DatetimeField(None)

    def validateActionSign(self, action_sign):
        pass
    def validateImsi(self, imsi):
        pass
    def validateMsisdn(self, msisdn):
        pass
    def validateGkId(self, gk_id):
        pass
    def validateIptId(self, ipt_id):
        pass
    def validateStatusCode(self, status_code):
        pass
    def validateSmsDatetime(self, sms_datetime):
        pass
    def validateEnterenceDatetime(self, enterence_datetime):
        pass
    def validatePayDatetime(self, pay_datetime):
        pass
    def validateLeaveDatetime(self, leave_datetime):
        pass
    def validateExitDatetime(self, exit_datetime):
        pass
    def validateAmount(self, amount):
        pass
    def validateCurrency(self, currency):
        pass
    def validateIptIdList(self, ipt_id_list):
        pass
    def validateTimestamp(self, timestamp):
        pass
    def setActionSign(self, action_sign):
        self.validateActionSign(action_sign)
        self._action_sign.setValue(action_sign)
    def setImsi(self, imsi):
        self.validateImsi(imsi)
        self._imsi.setValue(imsi)
    def setMsisdn(self, msisdn):
        self.validateMsisdn(msisdn)
        self._msisdn.setValue(msisdn)
    def setGkId(self, gk_id):
        self.validateGkId(gk_id)
        self._gk_id.setValue(gk_id)
    def setIptId(self, ipt_id):
        self.validateIptId(ipt_id)
        self._ipt_id.setValue(ipt_id)
    def setStatusCode(self, status_code):
        self.validateStatusCode(status_code)
        self._status_code.setValue(status_code)
    def setSmsDatetime(self, sms_datetime):
        self.validateSmsDatetime(sms_datetime)
        self._sms_datetime.setValue(sms_datetime)
    def setEnterenceDatetime(self, enterence_datetime):
        self.validateEnterenceDatetime(enterence_datetime)
        self._enterence_datetime.setValue(enterence_datetime)
    def setPayDatetime(self, pay_datetime):
        self.validatePayDatetime(pay_datetime)
        self._pay_datetime.setValue(pay_datetime)
    def setLeaveDatetime(self, leave_datetime):
        self.validateLeaveDatetime(leave_datetime)
        self._leave_datetime.setValue(leave_datetime)
    def setExitDatetime(self, exit_datetime):
        self.validateExitDatetime(exit_datetime)
        self._exit_datetime.setValue(exit_datetime)
    def setAmount(self, amount):
        self.validateAmount(amount)
        self._amount.setValue(amount)
    def setCurrency(self, currency):
        self.validateCurrency(currency)
        self._currency.setValue(currency)
    def setIptIdList(self, ipt_id_list):
        self.validateIptIdList(ipt_id_list)
        self._ipt_id_list.setValue(ipt_id_list)
    def setTimestamp(self, timestamp):
        self.validateTimestamp(timestamp)
        self._timestamp.setValue(timestamp)
    def getActionSign(self):
        return self._action_sign.getValue()
    def getImsi(self):
        return self._imsi.getValue()
    def getMsisdn(self):
        return self._msisdn.getValue()
    def getGkId(self):
        return self._gk_id.getValue()
    def getIptId(self):
        return self._ipt_id.getValue()
    def getStatusCode(self):
        return self._status_code.getValue()
    def getSmsDatetime(self):
        return self._sms_datetime.getValue()
    def getEnterenceDatetime(self):
        return self._enterence_datetime.getValue()
    def getPayDatetime(self):
        return self._pay_datetime.getValue()
    def getLeaveDatetime(self):
        return self._leave_datetime.getValue()
    def getExitDatetime(self):
        return self._exit_datetime.getValue()
    def getAmount(self):
        return self._amount.getValue()
    def getCurrency(self):
        return self._currency.getValue()
    def getIptIdList(self):
        return self._ipt_id_list.getValue()
    def getTimestamp(self):
        return self._timestamp.getValue()
    def writeActionSign(self, stream):
        tell_start = stream.tell()
        try:
            value = self.getActionSign()
            stream.write("\t{0:02d}".format(value))
        except ValueError:
            stream.write("\t")
        tell_end = stream.tell()
        return tell_end - tell_start
    def writeImsi(self, stream):
        tell_start = stream.tell()
        try:
            value = self.getImsi()
            stream.write("\t{0:02d}".format(value))
        except ValueError:
            stream.write("\t")
        tell_end = stream.tell()
        return tell_end - tell_start
    def writeMsisdn(self, stream):
        tell_start = stream.tell()
        try:
            value = self.getMsisdn()
            stream.write("\t{0:s}".format(value[:12]))
        except ValueError:
            stream.write("\t")
        tell_end = stream.tell()
        return tell_end - tell_start
    def writeGkId(self, stream):
        tell_start = stream.tell()
        try:
            value = self.getGkId()
            stream.write("\t{0:s}".format(value[:15]))
        except ValueError:
            stream.write("\t")
        tell_end = stream.tell()
        return tell_end - tell_start
    def writeIptId(self, stream):
        tell_start = stream.tell()
        try:
            value = self.getIptId()
            stream.write("\t{0:s}".format(value[:9]))
        except ValueError:
            stream.write("\t")
        tell_end = stream.tell()
        return tell_end - tell_start
    def writeStatusCode(self, stream):
        tell_start = stream.tell()
        try:
            value = self.getStatusCode()
            stream.write("\t{0:02d}".format(value))
        except ValueError:
            stream.write("\t")
        tell_end = stream.tell()
        return tell_end - tell_start
    def writeSmsDatetime(self, stream):
        tell_start = stream.tell()
        try:
            value = self.getSmsDatetime().strftime(self.DATETIME_FORMAT)
            stream.write("\t{0:s}".format(value[:12]))
        except ValueError:
            stream.write("\t")
        tell_end = stream.tell()
        return tell_end - tell_start
    def writeEnterenceDatetime(self, stream):
        tell_start = stream.tell()
        try:
            value = self.getEnterenceDatetime().strftime(self.DATETIME_FORMAT)
            stream.write("\t{0:s}".format(value[:12]))
        except ValueError:
            stream.write("\t")
        tell_end = stream.tell()
        return tell_end - tell_start
    def writePayDatetime(self, stream):
        tell_start = stream.tell()
        try:
            value = self.getPayDatetime().strftime(self.DATETIME_FORMAT)
            stream.write("\t{0:s}".format(value[:12]))
        except ValueError:
            stream.write("\t")
        tell_end = stream.tell()
        return tell_end - tell_start
    def writeLeaveDatetime(self, stream):
        tell_start = stream.tell()
        try:
            value = self.getLeaveDatetime().strftime(self.DATETIME_FORMAT)
            stream.write("\t{0:s}".format(value[:12]))
        except ValueError:
            stream.write("\t")
        tell_end = stream.tell()
        return tell_end - tell_start
    def writeExitDatetime(self, stream):
        tell_start = stream.tell()
        try:
            value = self.getExitDatetime().strftime(self.DATETIME_FORMAT)
            stream.write("\t{0:s}".format(value[:12]))
        except ValueError:
            stream.write("\t")
        tell_end = stream.tell()
        return tell_end - tell_start
    def writeAmount(self, stream):
        tell_start = stream.tell()
        try:
            value = int(self.getAmount()*100)
            stream.write("\t{0:06d}".format(value))
        except ValueError:
            stream.write("\t")
        tell_end = stream.tell()
        return tell_end - tell_start
    def writeCurrency(self, stream):
        tell_start = stream.tell()
        try:
            value = self.getCurrency()
            stream.write("\t{0:s}".format(value[:3]))
        except ValueError:
            stream.write("\t")
        tell_end = stream.tell()
        return tell_end - tell_start
    def writeIptIdList(self, stream):
        tell_start = stream.tell()
        try:
            value = self.getIptIdList()
            stream.write("\t{0:s}".format(value[:50]))
        except ValueError:
            stream.write("\t")
        tell_end = stream.tell()
        return tell_end - tell_start
    def writeTimestamp(self, stream):
        tell_start = stream.tell()
        try:
            value = self.getTimestamp().strftime(self.TIMESTAMP_FORMAT)
            stream.write("\t{0:s}000".format(value[:17]))
        except ValueError:
            stream.write("\t")
        tell_end = stream.tell()
        return tell_end - tell_start
    def writeToStream(self, stream):
        tell_start = stream.tell()
        self.writeActionSign(stream)
        self.writeImsi(stream)
        self.writeMsisdn(stream)
        self.writeGkId(stream)
        self.writeIptId(stream)
        self.writeStatusCode(stream)
        self.writeSmsDatetime(stream)
        self.writeEnterenceDatetime(stream)
        self.writePayDatetime(stream)
        self.writeLeaveDatetime(stream)
        self.writeExitDatetime(stream)
        self.writeAmount(stream)
        self.writeCurrency(stream)
        self.writeIptIdList(stream)
        self.writeTimestamp(stream)
        stream.write("\r\n")
        tell_end = stream.tell()
        return tell_end - tell_start
    def readActionSign(self, stream):
        delimiters = ["\t"]
        strField = readField(stream, delimiters)
        if strField == "":
            value = None
        else:
            value = int(strField)
        self.setActionSign(value)
        return value
    def readImsi(self, stream):
        delimiters = ["\t"]
        strField = readField(stream, delimiters)
        if strField == "":
            value = None
        else:
            value = int(strField)
        self.setImsi(value)
        return value
    def readMsisdn(self, stream):
        delimiters = ["\t"]
        strField = readField(stream, delimiters)
        if strField == "":
            value = None
        else:
            value = strField
        self.setMsisdn(value)
        return value
    def readGkId(self, stream):
        delimiters = ["\t"]
        strField = readField(stream, delimiters)
        if strField == "":
            value = None
        else:
            value = strField
        self.setGkId(value)
        return value
    def readIptId(self, stream):
        delimiters = ["\t"]
        strField = readField(stream, delimiters)
        if strField == "":
            value = None
        else:
            value = strField
        self.setIptId(value)
        return value
    def readStatusCode(self, stream):
        delimiters = ["\t"]
        strField = readField(stream, delimiters)
        if strField == "":
            value = None
        else:
            value = int(strField)
        self.setStatusCode(value)
        return value
    def readSmsDatetime(self, stream):
        delimiters = ["\t"]
        strField = readField(stream, delimiters)
        if strField == "":
            value = None
        else:
            value = datetime.strptime(strField, self.DATETIME_FORMAT)
        self.setSmsDatetime(value)
        return value
    def readEnterenceDatetime(self, stream):
        delimiters = ["\t"]
        strField = readField(stream, delimiters)
        if strField == "":
            value = None
        else:
            value = datetime.strptime(strField, self.DATETIME_FORMAT)
        self.setEnterenceDatetime(value)
        return value
    def readPayDatetime(self, stream):
        delimiters = ["\t"]
        strField = readField(stream, delimiters)
        if strField == "":
            value = None
        else:
            value = datetime.strptime(strField, self.DATETIME_FORMAT)
        self.setPayDatetime(value)
        return value
    def readLeaveDatetime(self, stream):
        delimiters = ["\t"]
        strField = readField(stream, delimiters)
        if strField == "":
            value = None
        else:
            value = datetime.strptime(strField, self.DATETIME_FORMAT)
        self.setLeaveDatetime(value)
        return value
    def readExitDatetime(self, stream):
        delimiters = ["\t"]
        strField = readField(stream, delimiters)
        if strField == "":
            value = None
        else:
            value = datetime.strptime(strField, self.DATETIME_FORMAT)
        self.setExitDatetime(value)
        return value
    def readAmount(self, stream):
        delimiters = ["\t"]
        strField = readField(stream, delimiters)
        if strField == "":
            value = None
        else:
            value = float(int(strField))/100.0
        self.setAmount(value)
        return value
    def readCurrency(self, stream):
        delimiters = ["\t"]
        strField = readField(stream, delimiters)
        if strField == "":
            value = None
        else:
            value = strField
        self.setCurrency(value)
        return value
    def readIptIdList(self, stream):
        delimiters = ["\t"]
        strField = readField(stream, delimiters)
        if strField == "":
            value = None
        else:
            value = strField
        self.setIptIdList(value)
        return value
    def readTimestamp(self, stream):
        delimiters = ["\r"]
        strField = readField(stream, delimiters)
        stream.read(1) # read \n
        if strField == "":
            value = None
        else:
            value = datetime.strptime(strField[:14], self.TIMESTAMP_FORMAT)
        self.setTimestamp(value)
        return value
    def readFromStream(self, stream):
        stream.read(1) #read the first \t
        self.readActionSign(stream)
        self.readImsi(stream)
        self.readMsisdn(stream)
        self.readGkId(stream)
        self.readIptId(stream)
        self.readStatusCode(stream)
        self.readSmsDatetime(stream)
        self.readEnterenceDatetime(stream)
        self.readPayDatetime(stream)
        self.readLeaveDatetime(stream)
        self.readExitDatetime(stream)
        self.readAmount(stream)
        self.readCurrency(stream)
        self.readIptIdList(stream)
        self.readTimestamp(stream)
        return self
    def readFromString(self, buff):
        buff_stream = StringIO(buff)
        bytes_read = self.readFromStream(buff_stream)
        buff_stream.close()
        return bytes_read
    def __str__(self):
        return "ACTION_SIGN:{0:s}\n".format(str(self._action_sign._value)) + \
        "IMSI:{0:s}\n".format(str(self._imsi._value)) + \
        "MSISDN:{0:s}\n".format(str(self._msisdn._value)) + \
        "GK_ID:{0:s}\n".format(str(self._gk_id._value)) + \
        "IPT_ID:{0:s}\n".format(str(self._ipt_id._value)) + \
        "STATUS_CODE:{0:s}\n".format(str(self._status_code._value)) + \
        "SMS_DATETIME:{0:s}\n".format(str(self._sms_datetime._value)) + \
        "ENTERENCE_DATETIME:{0:s}\n".format(str(self._enterence_datetime._value)) + \
        "PAY_DATETIME:{0:s}\n".format(str(self._pay_datetime._value)) + \
        "LEAVE_DATETIME:{0:s}\n".format(str(self._leave_datetime._value)) + \
        "EXIT_DATETIME:{0:s}\n".format(str(self._exit_datetime._value)) + \
        "AMOUNT:{0:s}\n".format(str(self._amount._value)) + \
        "CURRENCY:{0:s}\n".format(str(self._currency._value)) + \
        "IPT_ID_LIST:{0:s}\n".format(str(self._ipt_id_list._value)) + \
        "TIMESTAMP:{0:s}\n".format(str(self._timestamp._value))
    
class PDU():
    hdr = Header()
    body = Body()

    def readFromStream(self, stream):
        self.hdr.readFromStream(stream)
        self.body.readFromStream(stream)
        return self
    def writeToStream(self, stream):
        strmBody = StringIO("")
        self.body.writeToStream(strmBody)
        self.hdr.setPkgSize(len(strmBody.getvalue()) + self.hdr.APP_ID_SZ + self.hdr.PKG_SIZE_SZ)
        strmHdr = StringIO("")
        self.hdr.writeToStream(strmHdr)
        stream.write(strmHdr.getvalue() + strmBody.getvalue())
        return len(strmHdr.getvalue()) + len(strmBody.getvalue())
    def __str__(self):
        return str(self.hdr) + str(self.body)
    def __init__(self):
        pass

class BodyCalculatePriceReq(Body):
    def __init__(self):
        self.setActionSign(ActionSigns["CalculatePriceRequest"])
    def validateActionSign(self, action_sign):
        if action_sign is None:
            raise ValueError("missing action sign!")
        valid = ActionSigns["CalculatePriceRequest"]
        if action_sign != valid:
            raise ValueError("invalid action sign " + str(action_sign))
    def validateImsi(self, imsi):
        if imsi is None:
            raise ValueError("missing imsi!")
        valid = IMSI
        if imsi not in valid:
            raise ValueError("invalid imsi!")
    def validateGkId(self, gk_id):
        if gk_id is None:
            raise ValueError("missing gk id!")
    def validateIptId(self, ipt_id):
        if ipt_id is None:
            raise ValueError("missing ipt id!")
    def validateStatusCode(self, status_code):
        if status_code is None:
            raise ValueError("missing status code!")
        valid = StatusCodes
        if status_code not in valid:
            raise ValueError("invalid status code")
    def validateSmsDatetime(self, sms_datetime):
        if sms_datetime is None:
            raise ValueError("missing sms datetime!")
    def validateTimestamp(self, timestamp):
        if timestamp is None:
            raise ValueError("missing timestamp!")

class BodyCalculatePriceResp(Body):
    def __init__(self):
        self.setActionSign(ActionSigns["CalculatePriceResponse"])
    def validateActionSign(self, action_sign):
        if action_sign is None:
            raise ValueError("missing action sign!")
        valid = ActionSigns["CalculatePriceResponse"]
        if action_sign != valid:
            raise ValueError("invalid action sign " + str(action_sign))
    def validateImsi(self, imsi):
        if imsi is None:
            raise ValueError("missing imsi!")
        valid = IMSI
        if imsi not in valid:
            raise ValueError("invalid imsi!")
    def validateGkId(self, gk_id):
        if gk_id is None:
            raise ValueError("missing gk id!")
    def validateIptId(self, ipt_id):
        if ipt_id is None:
            raise ValueError("missing ipt id!")
    def validateStatusCode(self, status_code):
        if status_code is None:
            raise ValueError("missing status code!")
        valid = StatusCodes
        if status_code not in valid:
            raise ValueError("invalid status code")
    def validateEnterenceDatetime(self, enterence_datetime):
        if enterence_datetime is None:
            raise ValueError("missing enterence datetime!")
    def validatePayDatetime(self, pay_datetime):
        if pay_datetime is None:
            raise ValueError("missing pay datetime!")
    def validateLeaveDatetime(self, leave_datetime):
        if leave_datetime is None:
            raise ValueError("missing leave datetime!")
    def validateExitDatetime(self, exit_datetime):
        if exit_datetime is None:
            raise ValueError("missing exit datetime!")
    def validateAmount(self, amount):
        if amount is None:
            raise ValueError("missing amount!")
        if amount < 0.0:
            raise ValueError("invalid amount")
    def validateCurrency(self, currency):
        if currency is None:
            raise ValueError("missing currency!")
        valid = Currencies
        if currency.upper() not in valid:
            raise ValueError("invalid currency")
    def validateTimestamp(self, timestamp):
        if timestamp is None:
            raise ValueError("missing timestamp!")

class BodyTransactionStatus(Body):
    def validateActionSign(self, action_sign):
        if action_sign is None:
            raise ValueError("missing action sign!")
        valid = ActionSigns["TransactionStatus"]
        if action_sign != valid:
            raise ValueError("invalid action sign " + str(action_sign))
    def validateImsi(self, imsi):
        if imsi is None:
            raise ValueError("missing imsi!")
        valid = IMSI
        if imsi not in valid:
            raise ValueError("invalid imsi!")
    def validateGkId(self, gk_id):
        if gk_id is None:
            raise ValueError("missing gk id!")
    def validateIptId(self, ipt_id):
        if ipt_id is None:
            raise ValueError("missing ipt id!")
    def validateStatusCode(self, status_code):
        if status_code is None:
            raise ValueError("missing status code!")
        valid = StatusCodes
        if status_code not in valid:
            raise ValueError("invalid status code")
    def validateTimestamp(self, timestamp):
        if timestamp is None:
            raise ValueError("missing timestamp!")

class BodyTransactionSuccess(Body):
    def __init__(self):
        self.setActionSign(ActionSigns["TransactionSuccess"])
    def validateActionSign(self, action_sign):
        if action_sign is None:
            raise ValueError("missing action sign!")
        valid = ActionSigns["TransactionSuccess"]
        if action_sign != valid:
            raise ValueError("invalid action sign " + str(action_sign))
    def validateImsi(self, imsi):
        if imsi is None:
            raise ValueError("missing imsi!")
        valid = IMSI
        if imsi not in valid:
            raise ValueError("invalid imsi!")
    def validateGkId(self, gk_id):
        if gk_id is None:
            raise ValueError("missing gk id!")
    def validateIptId(self, ipt_id):
        if ipt_id is None:
            raise ValueError("missing ipt id!")
    def validateStatusCode(self, status_code):
        if status_code is None:
            raise ValueError("missing status code!")
        valid = StatusCodes
        if status_code not in valid:
            raise ValueError("invalid status code")
    def validateTimestamp(self, timestamp):
        if timestamp is None:
            raise ValueError("missing timestamp!")

class BodyReminder(Body):
    def validateActionSign(self, action_sign):
        if action_sign is None:
            raise ValueError("missing action sign!")
        valid = ActionSigns["Reminder"]
        if action_sign != valid:
            raise ValueError("invalid action sign " + str(action_sign))
    def validateImsi(self, imsi):
        if imsi is None:
            raise ValueError("missing imsi!")
        valid = IMSI
        if imsi not in valid:
            raise ValueError("invalid imsi!")
    def validateGkId(self, gk_id):
        if gk_id is None:
            raise ValueError("missing gk id!")
    def validateIptId(self, ipt_id):
        if ipt_id is None:
            raise ValueError("missing ipt id!")
    def validateStatusCode(self, status_code):
        if status_code is None:
            raise ValueError("missing status code!")
        valid = StatusCodes
        if status_code not in valid:
            raise ValueError("invalid status code")
    def validateTimestamp(self, timestamp):
        if timestamp is None:
            raise ValueError("missing timestamp!")

class PDUCalculatePriceReq(PDU):
    def __init__(self):
        self.body = BodyCalculatePriceReq()

class PDUCalculatePriceResp(PDU):
    def __init__(self):
        self.body = BodyCalculatePriceResp()

class PDUTransactionStatus(PDU):
    def __init__(self):
        self.body = BodyTransactionStatus()

class PDUTransactionSuccess(PDU):
    def __init__(self):
        self.body = BodyTransactionSuccess()

class PDUReminder(PDU):
    def __init__(self):
        self.body = BodyReminder()

StatusCodes = {
    0: "OK",
    1: "NOK",
    2: "unknown GK_ID",
    3: "unknown IPT_ID",
    4: "NO GSM operater",
    50: "System check",
    51: "Syntax error"
}
def StatusCodeFromString(strStatusCode):
    for intStatusCode in StatusCodes:
        if StatusCodes[intStatusCode].lower() == strStatusCode.lower():
            return intStatusCode

IMSI = [98,95,91]
ActionSigns = {
    "CalculatePriceRequest": 1,
    "CalculatePriceResponse": 2,
    "TransactionStatus": 3,
    "TransactionSuccess": 4,
    "Reminder": 5
}

Currencies = ["HRK"]

def StringToStream(buff):
    return StringIO(buff)
def StreamToString(stream):
    stream.getvalue()